package com.shangxia.lucky.lucky.job;

import com.google.common.collect.Lists;
import com.shangxia.lucky.common.util.file.ReadTXTUtil;
import com.shangxia.lucky.lucky.ConfigText;
import com.shangxia.lucky.lucky.entity.Model;
import com.shangxia.lucky.lucky.job.write.OverWriterThread;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;

import java.io.IOException;
import java.util.*;

import static com.shangxia.lucky.lucky.job.write.OverWriterThread.EXPORT_COLUMNS;


/**
 * @ProjectName: monomer
 * @ClassName: MatchJob
 * @Time: 2021/9/2
 * @Author: zhouy
 * @Description:
 * @Experience:
 */

@Slf4j
public abstract class BaseJob {

    public static List<Integer> ORDER_LIST = new ArrayList<>();
    public static List<List<Integer>> ROW_OVER_LIST = new ArrayList<>();
    public static List<List<Integer>> ROW_OVER_LAST_LIST = new ArrayList<>();
    public static Map<String, Model> ROW_MODELS = new HashMap<>();
    public static Map<String, Model> ROW_LAST_MODELS = new HashMap<>();

    public static List<Integer> LAST_LIST = new ArrayList<>();

    public volatile static Boolean BASE_FLAG_OVER = false;

    @Autowired
    public ConfigText configText;

    /**
     * 參考可信job
     *
     * @throws IOException
     */
    public void job() throws IOException {
        OverWriterThread overWriterThread = new OverWriterThread(configText);

        //开始准备输出翻层结果
        if (configText.getBananaOverExportOpen()) {
            new Thread(overWriterThread).start();
        }

        Map<String, Object> params = new HashMap<>();
        List<List<Integer>> lists = readCode(configText, configText.getBananaRealCodeFileName());
        turnOver(params, lists, configText);
        if (configText.getBananaOverExportOpen()) {
            overWriterThread.stop();
        }
        BASE_FLAG_OVER = true;
        logOver();
        System.exit(1);
    }

    /**
     * 读取号码
     *
     * @param fileName
     * @return
     * @throws IOException
     */
    List<List<Integer>> readCode(ConfigText configText, String fileName) throws IOException {
        return ReadTXTUtil.readRealCode(configText.getBananaAbsolutePath(), fileName);
    }

    public void turnOver(Map<String, Object> params, List<List<Integer>> realCodeLists, ConfigText configText) {
        for (int row = 0; row < realCodeLists.size(); row++) {
            params.put("row", row);
            //翻表开始 begin
            if (row % 100 == 0) {
                log.info("计算第 {} 行", 1 + row);
            }
            for (int column = 0; column <= Math.min(row, configText.getBananaOverMaxColumn() - 1); column++) {
                params.put("column", column);
                List<Integer> columnList;
                if (row == 0) {
                    columnList = new ArrayList<>(orderList(configText.bananaCodeLength));
                    columnList.removeAll(realCodeLists.get(0));
                    columnList.addAll(realCodeLists.get(0));
                } else if (column == 0) {
                    ArrayList<Integer> lastRowColumnList = new ArrayList<>(ROW_OVER_LAST_LIST.get(0));
                    lastRowColumnList.removeAll(realCodeLists.get(row));
                    lastRowColumnList.addAll(realCodeLists.get(row));
                    columnList = lastRowColumnList;
                } else {
                    List<Integer> lastColumnList = new ArrayList(ROW_OVER_LIST.get(column - 1));
                    List<Integer> realCodes = new ArrayList();
                    for (int i = 0; i < configText.getBananaSonCodeLength(); i++) {
                        realCodes.add(ROW_OVER_LAST_LIST.get(column - 1)
                                .indexOf(lastColumnList.get(configText.getBananaCodeLength() - configText.getBananaSonCodeLength() + i)) + 1);
                    }
                    if (ROW_OVER_LAST_LIST.size() < column + 2) {
                        columnList = new ArrayList(ORDER_LIST);
                    } else {
                        columnList = new ArrayList(ROW_OVER_LAST_LIST.get(column));
                    }
                    columnList.removeAll(realCodes);
                    columnList.addAll(realCodes);
                }

                ROW_OVER_LIST.add(columnList);
                //翻表开始 end
                //计算匹配情况
                params.put("columnList", columnList);
                doPrivateJob(params, realCodeLists);

            }
            //本层分析计算结束

            //输出翻层结果
            exportOverResult(ROW_OVER_LAST_LIST, row, ROW_OVER_LIST, configText);

            //输出本层结果
            params.put("maxRow", realCodeLists.size());
            exportRowResult(params);

            //重置中间层数据
            ROW_OVER_LAST_LIST = new ArrayList<>(ROW_OVER_LIST);
            ROW_OVER_LIST.clear();
            ROW_LAST_MODELS = new HashMap<>(ROW_MODELS);
            ROW_MODELS.clear();
        }
        //输出最后一层翻层结果
        exportLstOverRowResult(ROW_OVER_LAST_LIST, realCodeLists.size());
        //输出最后一层结果
        exportLastRowResult();

    }

    public abstract void logOver();

    /**
     * 初始化最後一行
     *
     * @param column
     */
    public abstract void initLAST_LIST(Integer column);

    public abstract void lastRowData(List<Model> resultList);

    public void exportLstOverRowResult(List<List<Integer>> rowOverLastList, int size) {
        if (!configText.getBananaOverExportOpen() || ObjectUtils.isEmpty(OverWriterThread.mapQueue)) {
            return;
        }
        for (Integer exportColumn : EXPORT_COLUMNS) {
            List<List<String>> exportList = new ArrayList<>();
            List<String> list0 = new ArrayList<>();
            list0.add(size + "");
            try {
                rowOverLastList.get(exportColumn).stream().forEach(e -> {
                    list0.add("" + e);
                });
                exportList.add(list0);
            } catch (IndexOutOfBoundsException e) {
                exportList.add(new ArrayList<>());
            }
            OverWriterThread.mapQueue.get(exportColumn).add(exportList);
        }
    }

    public abstract void exportLastRowResult();

    public abstract void exportRowResult(Map<String, Object> params);

    /**
     * 递增连号
     *
     * @param limit
     * @return
     */
    List<Integer> orderList(Integer limit) {
        if (CollectionUtils.isEmpty(ORDER_LIST)) {
            for (int i = 1; i < limit + 1; i++) {
                ORDER_LIST.add(i);
            }
        }
        return ORDER_LIST;
    }


    public abstract void doPrivateJob(Map<String, Object> params, List<List<Integer>> realCodeLists);


    public void exportOverResult(List<List<Integer>> rowLastList, int row, List<List<Integer>> rowList, ConfigText configText) {
        if (!configText.bananaOverExportOpen || CollectionUtils.isEmpty(rowLastList) || CollectionUtils.isEmpty( OverWriterThread.WRITE_HANDLERS_MAP.keySet())) {
            return;
        }
        for (Integer exportColumn : EXPORT_COLUMNS) {

            List<List<String>> exportList = new ArrayList<>();
            List<String> list = new ArrayList<>();
            list.add(row + "");
            try {
                rowLastList.get(exportColumn).stream().forEach(e -> {
                    list.add("" + e);
                });
                exportList.add(list);
                List<String> transform = Lists.transform(rowList.get(exportColumn).subList(configText.getBananaCodeLength() - configText.getBananaSonCodeLength(), rowList.get(exportColumn).size()), num -> "" + num);
                OverWriterThread.WRITE_HANDLERS_MAP.get(exportColumn).getRedLastList().add(transform);
            } catch (IndexOutOfBoundsException e) {
                exportList.add(new ArrayList<>());
                OverWriterThread.WRITE_HANDLERS_MAP.get(exportColumn).getRedLastList().add(new ArrayList<>());
            }
            OverWriterThread.mapQueue.get(exportColumn).add(exportList);
        }

    }

    /**
     * </>List<List<Integer>> 转 List<List<String>>
     *
     * @param data
     * @return
     */
    public List<List<String>> changeListsInt2Str(List<List<Integer>> data) {
        List<List<String>> dataStr = new ArrayList<>();
        for (List<Integer> listI : data) {
            List<String> listStr = new ArrayList<>();
            listI.stream().forEach(e -> {
                listStr.add("" + e);
            });
            dataStr.add(listStr);
        }
        return dataStr;
    }

}
